﻿using ICodeShare.UI.Controls.Assists;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Shell;
using System.Xml;
using System.Xml.Serialization;

namespace ICodeShare.UI.Controls
{
    public class ExtraWindow:CustomWindowBase
    {
        #region Constants

        private const int OVERLAY_ICON_WIDTH = 16;
        private const int OVERLAY_ICON_HEIGHT = 16;

        #endregion

        private FieldInfo chromeField;

         #region Constructors

        /// <summary>
        /// Initialises static members of the <see cref="ExtraWindow"/> class.
        /// </summary>
        static ExtraWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ExtraWindow), new FrameworkPropertyMetadata(typeof(ExtraWindow)));

            MarginProperty.OverrideMetadata(typeof(ExtraWindow), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnMarginPropertyChanged)));
        }

        /// <summary>
        /// Initialises a new instance of the <see cref="ExtraWindow"/> class.
        /// </summary>
        public ExtraWindow()
        {
            this.KeyUp += this.OnKeyUp;

            this.Style = (Style)this.FindResource(typeof(ExtraWindow));

            WindowAssist.SetMinimizeButtonToolTip(this, "Minimize");
            WindowAssist.SetMaximizeButtonToolTip(this, "Maximize");
            WindowAssist.SetRestoreButtonToolTip(this, "Restore");
            WindowAssist.SetCloseButtonToolTip(this, "Close");

            this.TaskbarItemInfo = new TaskbarItemInfo();
        }

        #endregion

        #region Dependency Properties

        #region Margin
         private static void OnMarginPropertyChanged(
            DependencyObject dependencyObject, 
            DependencyPropertyChangedEventArgs e)
        {
            ExtraWindow window = (ExtraWindow)dependencyObject;
            window.UpdateResizeBorderThickness();
        }

        #endregion

         #region CanFullScreenHotKey

         /// <summary>
        /// Gets or sets a value indicating whether is full screen shortcuts enabled.
        /// </summary>
        public bool CanFullScreenHotKey
        {
            get { return (bool)this.GetValue(CanFullScreenHotKeyProperty); }
            set { this.SetValue(CanFullScreenHotKeyProperty, value); }
        }

        public static readonly DependencyProperty CanFullScreenHotKeyProperty = DependencyProperty.Register(
          "CanFullScreenHotKey",
          typeof(bool),
          typeof(ExtraWindow),
          new PropertyMetadata(true));

        #endregion

        #region IsFullScreen

        /// <summary>
        /// Gets or sets a value indicating whether is full screen.
        /// </summary>
        public bool IsFullScreen
        {
            get { return (bool)this.GetValue(IsFullScreenProperty); }
            set { this.SetValue(IsFullScreenProperty, value); }
        }

        public static readonly DependencyProperty IsFullScreenProperty = DependencyProperty.Register(
           "IsFullScreen",
           typeof(bool),
           typeof(ExtraWindow),
           new PropertyMetadata(false));

        #endregion

        #region TaskbarIsBusy

        /// <summary>
        /// Gets or sets a value indicating whether the taskbar progress bar should be shown as indeterminate.
        /// </summary>
        /// <value>
        /// <c>true</c> if the taskbar is busy; otherwise, <c>false</c>.
        /// </value>
        public bool TaskbarIsBusy
        {
            get { return (bool)this.GetValue(TaskbarIsBusyProperty); }
            set { this.SetValue(TaskbarIsBusyProperty, value); }
        }

        public static readonly DependencyProperty TaskbarIsBusyProperty = DependencyProperty.Register(
            "TaskbarIsBusy",
            typeof(bool),
            typeof(ExtraWindow),
            new PropertyMetadata(false, OnTaskbarIsBusyPropertyChanged));

        /// <summary>
        /// Called when the taskbar is busy property is changed.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnTaskbarIsBusyPropertyChanged(
            DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs e)
        {
            ExtraWindow window = (ExtraWindow)dependencyObject;

            if (window.TaskbarIsBusy)
            {
                window.GetTaskbarItemInfoSafely().ProgressState = TaskbarItemProgressState.Indeterminate;
            }
            else
            {
                window.GetTaskbarItemInfoSafely().ProgressState = TaskbarItemProgressState.None;
            }
        }

        #endregion

        #region TaskbarProgressState

        /// <summary>
        /// Gets or sets the state of the taskbar progress.
        /// </summary>
        /// <value>
        /// The state of the taskbar progress.
        /// </value>
        public TaskbarItemProgressState TaskbarProgressState
        {
            get { return (TaskbarItemProgressState)this.GetValue(TaskbarProgressStateProperty); }
            set { this.SetValue(TaskbarProgressStateProperty, value); }
        }

        public static readonly DependencyProperty TaskbarProgressStateProperty = DependencyProperty.Register(
           "TaskbarProgressState",
           typeof(TaskbarItemProgressState),
           typeof(ExtraWindow),
           new PropertyMetadata(TaskbarItemProgressState.None, OnTaskbarProgressStatePropertyChanged));

        /// <summary>
        /// Called when the task bar progress state property is changed.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnTaskbarProgressStatePropertyChanged(
            DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs e)
        {
            ExtraWindow window = (ExtraWindow)dependencyObject;
            window.GetTaskbarItemInfoSafely().ProgressState = window.TaskbarProgressState;
        }

        #endregion

        #region TaskbarProgressValue

        /// <summary>
        /// Gets or sets the taskbar progress value.
        /// </summary>
        /// <value>
        /// The taskbar progress value.
        /// </value>
        public double TaskbarProgressValue
        {
            get { return (double)this.GetValue(TaskbarProgressValueProperty); }
            set { this.SetValue(TaskbarProgressValueProperty, value); }
        }

        public static readonly DependencyProperty TaskbarProgressValueProperty = DependencyProperty.Register(
           "TaskbarProgressValue",
           typeof(double),
           typeof(ExtraWindow),
           new PropertyMetadata(0D, OnTaskbarProgressValuePropertyChanged));

        /// <summary>
        /// Called when the task bar progress value property is changed.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnTaskbarProgressValuePropertyChanged(
            DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs e)
        {
            ExtraWindow window = (ExtraWindow)dependencyObject;
            window.GetTaskbarItemInfoSafely().ProgressValue = window.TaskbarProgressValue;
        }

        #endregion

        #region TaskbarDescription

        /// <summary>
        /// Gets or sets the taskbar description.
        /// </summary>
        /// <value>
        /// The taskbar description.
        /// </value>
        public string TaskbarDescription
        {
            get { return (string)this.GetValue(TaskbarDescriptionProperty); }
            set { this.SetValue(TaskbarDescriptionProperty, value); }
        }

        public static readonly DependencyProperty TaskbarDescriptionProperty = DependencyProperty.Register(
           "TaskbarDescription",
           typeof(string),
           typeof(ExtraWindow),
           new PropertyMetadata(null, OnTaskbarDescriptionPropertyChanged));

        /// <summary>
        /// Called when the task bar description property is changed.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnTaskbarDescriptionPropertyChanged(
            DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs e)
        {
            ExtraWindow window = (ExtraWindow)dependencyObject;
            window.GetTaskbarItemInfoSafely().Description = window.TaskbarDescription;
        }

        #endregion

        #region TaskbarOverlay

        /// <summary>
        /// Gets or sets the taskbar icon overlayed on top of the default icon.
        /// </summary>
        /// <value>
        /// The taskbar overlay.
        /// </value>
        public object TaskbarOverlay
        {
            get { return (object)this.GetValue(TaskbarOverlayProperty); }
            set { this.SetValue(TaskbarOverlayProperty, value); }
        }

        public static readonly DependencyProperty TaskbarOverlayProperty = DependencyProperty.Register(
           "TaskbarOverlay",
           typeof(object),
           typeof(ExtraWindow),
           new PropertyMetadata(null, OnTaskbarOverlayPropertyChanged));

        /// <summary>
        /// Called when the task bar overlay property is changed.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnTaskbarOverlayPropertyChanged(
            DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs e)
        {
            ExtraWindow window = (ExtraWindow)dependencyObject;

            if ((window.TaskbarOverlay == null) && (window.TaskbarOverlayTemplate == null))
            {
                window.GetTaskbarItemInfoSafely().Overlay = null;
            }
            else if ((window.TaskbarOverlay != null) && (window.TaskbarOverlay is ImageSource) && (window.TaskbarOverlayTemplate == null))
            {
                window.GetTaskbarItemInfoSafely().Overlay = (ImageSource)window.TaskbarOverlay;
            }

            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(
                OVERLAY_ICON_WIDTH,
                OVERLAY_ICON_HEIGHT,
                96,
                96,
                PixelFormats.Default);
            ContentControl contentControl = new ContentControl()
            {
                Content = window.TaskbarOverlay,
                ContentTemplate = window.TaskbarOverlayTemplate
            };
            contentControl.Arrange(new Rect(0, 0, OVERLAY_ICON_WIDTH, OVERLAY_ICON_HEIGHT));
            renderTargetBitmap.Render(contentControl);

            window.GetTaskbarItemInfoSafely().Overlay = renderTargetBitmap;
        }

        #endregion

        #region TaskbarOverlayTemplate

        /// <summary>
        /// Gets or sets the taskbar overlay template.
        /// </summary>
        /// <value>
        /// The taskbar overlay template.
        /// </value>
        public DataTemplate TaskbarOverlayTemplate
        {
            get { return (DataTemplate)this.GetValue(TaskbarOverlayTemplateProperty); }
            set { this.SetValue(TaskbarOverlayTemplateProperty, value); }
        }

        public static readonly DependencyProperty TaskbarOverlayTemplateProperty = DependencyProperty.Register(
            "TaskbarOverlayTemplate",
            typeof(DataTemplate),
            typeof(ExtraWindow),
            new PropertyMetadata(null, OnTaskbarOverlayPropertyChanged));

        #endregion

        #endregion

        #region Methods

        protected override void OnStateChanged(EventArgs e)
        {
            base.OnStateChanged(e);
            this.UpdateResizeBorderThickness();
        }

        /// <summary>
        /// Gets the taskbar item information safely.
        /// </summary>
        /// <returns></returns>
        private TaskbarItemInfo GetTaskbarItemInfoSafely()
        {
            if (this.TaskbarItemInfo == null)
            {
                this.TaskbarItemInfo = new TaskbarItemInfo();
            }

            if (this.TaskbarItemInfo.IsFrozen)
            {
                this.TaskbarItemInfo = (TaskbarItemInfo)this.TaskbarItemInfo.Clone();
            }

            return this.TaskbarItemInfo;
        }

        /// <summary>
        /// Called when the key up event is fired.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="KeyEventArgs"/> instance containing the event data.</param>
        private void OnKeyUp(object sender, KeyEventArgs e)
        {
            if (this.CanFullScreenHotKey)
            {
                if (e.Key == Key.F12)
                {
                    this.IsFullScreen = true;
                }
                else if (e.Key == Key.Escape)
                {
                    this.IsFullScreen = false;
                }
            }
        }

        private void UpdateResizeBorderThickness()
        {
            if (this.chromeField != null)
            {
                Microsoft.Windows.Shell.WindowChrome chrome = (Microsoft.Windows.Shell.WindowChrome)this.chromeField.GetValue(this);
                if (this.WindowState == WindowState.Maximized)
                {
                    chrome = new Microsoft.Windows.Shell.WindowChrome
                    {
                        CaptionHeight = chrome.CaptionHeight,
                        CornerRadius = chrome.CornerRadius,
                        GlassFrameThickness = chrome.GlassFrameThickness,
                        NonClientFrameEdges = chrome.NonClientFrameEdges,
                        ResizeBorderThickness = new Thickness(0D),
                        UseAeroCaptionButtons = chrome.UseAeroCaptionButtons
                    };
                }
                else
                {
                    chrome = new Microsoft.Windows.Shell.WindowChrome
                    {
                        CaptionHeight = chrome.CaptionHeight,
                        CornerRadius = chrome.CornerRadius,
                        GlassFrameThickness = chrome.GlassFrameThickness,
                        NonClientFrameEdges = chrome.NonClientFrameEdges,
                        ResizeBorderThickness = new Thickness(
                            this.Margin.Left < 3D ? 3D : this.Margin.Left,
                            this.Margin.Top < 3D ? 3D : this.Margin.Top,
                            this.Margin.Right < 3D ? 3D : this.Margin.Right,
                            this.Margin.Bottom < 3D ? 3D : this.Margin.Bottom),
                        UseAeroCaptionButtons = chrome.UseAeroCaptionButtons
                    };
                }
                chrome.Freeze();
                Microsoft.Windows.Shell.WindowChrome.SetWindowChrome(this, chrome);
            }
        }
        #endregion
    }
}
